"""
author: liuxu
date: 2025/7/9
description: 封装文件，目录等操作
"""
import os
import shutil
import glob
import tempfile
from typing import List, Optional, Tuple
from common.logger_ctrl import mylogger


class OSUtils:
    """用于操作系统自动化测试的工具类"""

    @staticmethod
    def create_directory(path, clean = True) -> bool:
        """
        安全创建目录（自动创建父目录）

        Args:
            path: 要创建的目录路径
            clean: 目录已存在时先删除（默认True）

        Returns:
            成功True
            失败False
        """
        abs_path = os.path.abspath(path)
        try:
            if clean and os.path.exists(path):
                shutil.rmtree(path)
                mylogger.debug(f"Deleted {path}")
            os.makedirs(abs_path, exist_ok=True)
            mylogger.debug(f"Succeed to mkdir {path}")
            return True
        except Exception as e:
            mylogger.error(f"Failed to create directory: {abs_path}, error: {str(e)}")
            return False

    @staticmethod
    def create_text_file(
            path: str,
            content: str = "",
            overwrite: bool = True,
            encoding: str = "utf-8"
    ) -> bool:
        """
        创建文本文件并写入内容（自动创建父目录）

        Args:
            path: 文件路径
            content: 文件内容（默认空）
            overwrite: 覆盖已存在文件（默认True）
            encoding: 文件编码（默认utf-8）

        Returns:
            True: 成功
            False: 失败
        """
        abs_path = os.path.abspath(path)
        dir_path = os.path.dirname(abs_path)

        if overwrite is not True and os.path.exists(abs_path):
            mylogger.error(f"[FileExistsError]File already exists and overwrite not allowed: {abs_path}")
            return False

        try:
            # 确保父目录存在
            if not os.path.isdir(dir_path):
                os.makedirs(dir_path, exist_ok=True)

            with open(abs_path, 'w', encoding=encoding) as f:
                f.write(content)
                mylogger.debug(f"Succeed to create and write {abs_path}, content:\n {content}")
            return True
        except Exception as e:
            mylogger.error(f"Failed to write file: {abs_path}, error: {str(e)}")
            return False

    @staticmethod
    def read_text_file(file_name: str, encoding: str = "utf-8") -> str:
        """
        读取文本文件内容

        Args:
            file_name: 文件路径
            encoding: 文件编码（默认utf-8）

        Returns:
            文件内容字符串
        """
        try:
            with open(file_name, 'r', encoding=encoding) as f:
                content = f.read()
                mylogger.info(f"Succeed to read {file_name}, content:\n {content}")
                return content
        except Exception as e:
            mylogger.error(f"Failed to read file: {file_name}, error: {str(e)}")
            return ""

    @staticmethod
    def path_exists(path: str) -> bool:
        """检查路径是否存在（文件或目录）"""
        return os.path.exists(path)

    @staticmethod
    def is_file(path: str) -> bool:
        """检查路径是否为文件"""
        return os.path.isfile(path)

    @staticmethod
    def is_directory(path: str) -> bool:
        """检查路径是否为目录"""
        return os.path.isdir(path)

    @staticmethod
    def glob_files(pattern: str) -> List[str]:
        """
        使用glob模式匹配文件（返回绝对路径）

        Args:
            pattern: glob模式，如"*.txt"

        Returns:
            匹配的文件绝对路径列表
        """
        return [os.path.abspath(f) for f in glob.glob(pattern)]

    @staticmethod
    def count_glob_matches(pattern: str) -> int:
        """统计匹配指定glob模式的文件数量"""
        return len(glob.glob(pattern))

    @staticmethod
    def delete_directory(path: str, force: bool = True) -> None:
        """
        删除目录（支持强制删除非空目录）

        Args:
            path: 目录路径
            force: 是否递归删除目录内容（默认True）
        """
        if not os.path.exists(path):
            return

        if not os.path.isdir(path):
            raise NotADirectoryError(f"Path is not a directory: {path}")

        try:
            if force:
                shutil.rmtree(path)
            else:
                os.rmdir(path)
        except Exception as e:
            mylogger.error(f"Failed to delete directory: {path}, error: {str(e)}")

    @staticmethod
    def delete_file(path: str) -> None:
        """删除文件（忽略不存在的文件）"""
        try:
            if os.path.isfile(path):
                os.remove(path)
        except Exception as e:
            mylogger.error(f"Failed to delete file: {path}, error: {str(e)}")

    @staticmethod
    def clear_directory(path: str) -> None:
        """清空目录内容（保留目录本身）"""
        if not os.path.isdir(path):
            raise NotADirectoryError(f"Path is not a directory: {path}")

        for item in os.listdir(path):
            item_path = os.path.join(path, item)
            if os.path.isfile(item_path):
                os.unlink(item_path)
            elif os.path.isdir(item_path):
                shutil.rmtree(item_path)

    @staticmethod
    def get_temp_dir(prefix: Optional[str] = None) -> str:
        """创建并返回临时目录路径（自动清理由调用方负责）"""
        return tempfile.mkdtemp(prefix=prefix)

    @staticmethod
    def get_temp_file(prefix: Optional[str] = None, suffix: Optional[str] = None) -> str:
        """创建并返回临时文件路径（文件已创建）"""
        fd, path = tempfile.mkstemp(prefix=prefix, suffix=suffix)
        os.close(fd)
        return path

    @staticmethod
    def copy_file(src: str, dst: str, overwrite: bool = True) -> str:
        """
        复制文件

        Args:
            src: 源文件路径
            dst: 目标文件路径
            overwrite: 是否覆盖已存在文件（默认True）

        Returns:
            目标文件绝对路径
        """
        abs_dst = os.path.abspath(dst)
        if os.path.exists(abs_dst) and not overwrite:
            raise FileExistsError(f"Destination file already exists: {abs_dst}")

        shutil.copy2(src, dst)
        return abs_dst

    @staticmethod
    def list_directory(path: str) -> Tuple[List[str], List[str]]:
        """
        列出目录内容

        Args:
            path: 目录路径

        Returns:
            (文件列表, 子目录列表) 的元组
        """
        files = []
        dirs = []

        for entry in os.listdir(path):
            full_path = os.path.join(path, entry)
            if os.path.isfile(full_path):
                files.append(entry)
            elif os.path.isdir(full_path):
                dirs.append(entry)

        return files, dirs


# 使用示例
if __name__ == "__main__":
    # 创建临时测试环境
    test_dir = OSTestUtils.get_temp_dir(prefix="automation_test_")
    print(f"Test directory: {test_dir}")

    try:
        # 1. 创建嵌套目录
        nested_dir = OSTestUtils.create_directory(os.path.join(test_dir, "level1/level2"))
        print(f"Created nested directory: {nested_dir}")

        # 2. 创建文本文件
        file_path = OSTestUtils.create_text_file(
            path=os.path.join(nested_dir, "data.txt"),
            content="第一行\n第二行\n第三行",
            overwrite=True
        )
        print(f"Created file: {file_path}")

        # 3. 读取文件验证
        content = OSTestUtils.read_text_file(file_path)
        print(f"File content: {content[:20]}...")

        # 4. 文件操作
        copied_file = OSTestUtils.copy_file(
            src=file_path,
            dst=os.path.join(test_dir, "backup.txt")
        )
        print(f"Copied file to: {copied_file}")

        # 5. 目录内容操作
        OSTestUtils.create_text_file(os.path.join(test_dir, "temp.log"), "日志内容")
        files, dirs = OSTestUtils.list_directory(test_dir)
        print(f"Main directory contents - Files: {files}, Directories: {dirs}")

        # 6. 清空目录测试
        OSTestUtils.clear_directory(nested_dir)
        print(f"Directory after clearing: {os.listdir(nested_dir)}")

        # 7. 模式匹配测试
        matches = OSTestUtils.glob_files(os.path.join(test_dir, "*.log"))
        print(f"Matched log files: {matches}")

    finally:
        # 清理测试环境
        OSTestUtils.delete_directory(test_dir, force=True)
        print(f"Cleaned up test directory: {test_dir}")
        print(f"Directory exists: {OSTestUtils.path_exists(test_dir)}")